import json
import time
from decimal import Decimal

from django import http
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db import transaction
from django.shortcuts import render, redirect
from django.urls import reverse
from django.utils import timezone
from django.views import View
from django_redis import get_redis_connection

from apps.areas.models import Address
from apps.goods.models import SKU
from apps.orders.models import OrderInfo, OrderGoods
from utils.response_code import RETCODE


class OrderSettlementView(LoginRequiredMixin, View):
    """订单页面"""

    def get(self, request):
        """提交订单页面的显示"""
        user = request.user

        # 查询用户的收货地址
        try:
            addresses = Address.objects.filter(user=user, is_deleted=False)
        except:
            addresses = None

        # 查询被选中的商品
        # 1.连接redis
        redis_conn = get_redis_connection('carts')

        # 2.查询选中的sku_id和carts
        carts = redis_conn.hgetall('carts_%s' % user.id)
        selected = redis_conn.smembers('selected_%s' % user.id)

        cart = {}
        # 遍历被选中商品的sku_id
        for sku_id in selected:
            cart[int(sku_id)] = int(carts[sku_id])

        total_count = 0
        total_amount = Decimal(0.00)

        # 取到sku_id从数据库中查询
        skus = SKU.objects.filter(id__in=cart.keys())

        for sku in skus:
            sku.count = cart[sku.id]
            sku.amount = sku.count * sku.price
            total_count += sku.count
            total_amount += sku.amount

        freight = Decimal(10.00)
        context = {
            'addresses': addresses,
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': freight,
            'payment_amount': total_amount + freight,
        }
        return render(request, 'place_order.html', context=context)


class OrderCommitView(View):

    # def post(self, request):
    #     """提交订单信息"""
    #
    #     # 获取参数
    #     json_dict = json.loads(request.body.decode())
    #     address_id = json_dict.get('address_id')  # 收货地址id
    #     pay_method = json_dict.get("pay_method")  # 支付方式
    #
    #     # 验证参数-------------------
    #     if not all([address_id, pay_method]):
    #         return http.HttpResponseBadRequest('参数不足')
    #
    #     try:
    #         address = Address.objects.get(id=address_id)
    #     except:
    #         return http.HttpResponseBadRequest("does not found the address")
    #
    #     if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
    #         return http.HttpResponseBadRequest("pay_method is not found")
    #
    #     # 获取登录用户
    #     user = request.user
    #
    #     # 生成订单编号
    #     order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)
    #     with transaction.atomic():
    #         save_id = transaction.savepoint()
    #         try:
    #             # 创建订单对象
    #             order = OrderInfo.objects.create(
    #                 order_id=order_id,
    #                 user=user,
    #                 address=address,
    #                 total_count=0,
    #                 total_amount=Decimal(0),
    #                 freight=Decimal(10.00),
    #                 pay_method=pay_method,
    #                 status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM[
    #                     'ALIPAY'] else
    #                 OrderInfo.ORDER_STATUS_ENUM['UNSEND']
    #             )
    #
    #             # 从redis中获取被选中的商品信息
    #             redis_conn = get_redis_connection('carts')
    #             # 购物车中商品
    #             redis_carts = redis_conn.hgetall('carts_%s' % user.id)
    #             # 被选中商品
    #             selected = redis_conn.smembers('selected_%s' % user.id)
    #             carts = {}
    #             for sku_id in selected:
    #                 carts[int(sku_id)] = int(redis_carts[sku_id])
    #             # 获取购物车被选中的所有sku_id
    #             skus_id = carts.keys()
    #
    #             for sku_id in skus_id:
    #                 # 查询sku信息
    #                 for sql_loop in range(3):
    #                     # 查询SKU信息
    #                     sku = SKU.objects.get(id=sku_id)
    #
    #                     # 商品再查询
    #                     origin_stock = sku.stock
    #                     origin_sales = sku.sales
    #
    #                     # 查询sku的库存
    #                     count = carts[sku_id]
    #                     if count > sku.stock:
    #                         transaction.savepoint_rollback(save_id)
    #                         response = http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})
    #                         return response
    #                     new_stock = origin_stock - sku.count
    #                     new_sales = origin_sales + sku.count
    #
    #                     result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock,
    #                                                                                       sales=new_sales)
    #
    #                     if result == 0:
    #                         if sql_loop == 2:
    #                             transaction.savepoint_rollback(save_id)
    #                             return http.JsonResponse({"code": RETCODE.STOCKERR, 'errmsg': '下单失败2'})
    #                         else:
    #                             continue
    #                     else:
    #                         break
    #
    #                 # 保存订单信息
    #                 OrderGoods.objects.create(
    #                     order=order,
    #                     sku=sku,
    #                     count=count,
    #                     price=sku.price,
    #                 )
    #                 # 保存商品订单中总价和总数量
    #                 order.total_amount += (count * sku.price)
    #                 order.total_count += count
    #
    #             # 添加邮费和保存订单信息
    #             order.total_amount += order.freight
    #             order.save()
    #         except:
    #             transaction.savepoint_rollback(save_id)
    #             return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '下单失败'})
    #         transaction.savepoint_commit(save_id)
    #     # 清除购物车中已加入订单商品
    #     pl = redis_conn.pipeline()
    #     pl.hdel('carts_%s' % user.id, *selected)
    #     pl.srem('selected_%s' % user.id, *selected)
    #     pl.execute()
    #     return http.JsonResponse({'code': RETCODE.OK, 'errmsg': "ok", 'order_id': order.order_id})

    def post(self, request):
        """保存订单信息和订单商品信息"""
        # 获取当前要保存的订单数据
        json_dict = json.loads(request.body.decode())
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')

        # 校验参数
        if not all([address_id, pay_method]):
            return http.HttpResponseBadRequest('缺少必传参数')
        # 判断address_id是否合法
        try:
            address = Address.objects.get(id=address_id)
            # 判断这个收货地址是否属于当前登录用户
            if address.user != request.user:
                # 如果不属于当前用户，那么返回错误信息信息
                return http.HttpResponseBadRequest('参数address_id错误')
        except Exception:
            return http.HttpResponseBadRequest('参数address_id错误')
        # 判断pay_method是否合法
        if int(pay_method) not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.HttpResponseBadRequest('参数pay_method错误')

        # 获取登录用户
        user = request.user
        # 生成订单编号：年月日时分秒+用户编号
        order_id = timezone.now().strftime('%Y%m%d%H%M%S') + '%09d' % user.id

        # 显式的开启一个事务
        with transaction.atomic():
            # 创建事务保存点
            save_id = transaction.savepoint()
            try:

                # 保存订单基本信息 OrderInfo（一）
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal('0'),
                    freight=Decimal('10.00'),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM[
                        'ALIPAY'] else
                    OrderInfo.ORDER_STATUS_ENUM['UNSEND']
                )

                # 从redis读取购物车中被勾选的商品信息
                redis_conn = get_redis_connection('carts')
                redis_cart = redis_conn.hgetall('carts_%s' % user.id)
                selected = redis_conn.smembers('selected_%s' % user.id)
                carts = {}
                for sku_id in selected:
                    carts[int(sku_id)] = int(redis_cart[sku_id])
                sku_ids = carts.keys()

                # 遍历购物车中被勾选的商品信息
                for sku_id in sku_ids:
                    # ------- 修改了代码-------
                    for sql_loop in range(3):
                        # 查询SKU信息
                        sku = SKU.objects.get(id=sku_id)

                        print("{}--正在下单id={}".format(request.user.username, sku_id))

                        # ------- 修改了代码-------
                        # 读取原始库存
                        origin_stock = sku.stock
                        origin_sales = sku.sales

                        # 判断SKU库存
                        sku_count = carts[sku.id]
                        if sku_count > origin_stock:
                            # 事务回滚
                            transaction.savepoint_rollback(save_id)
                            return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})

                        # 乐观锁更新库存和销量
                        new_stock = origin_stock - sku_count
                        new_sales = origin_sales + sku_count
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock,
                                                                                          sales=new_sales)
                        # 如果下单失败，但是库存足够时，继续下单，直到下单成功或者库存不足为止
                        if result == 0:
                            if sql_loop == 2:
                                # 事务回滚
                                transaction.savepoint_rollback(save_id)
                                return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '下单失败2'})
                            else:
                                continue
                        else:
                            break

                    # 保存订单商品信息 OrderGoods（多）
                    OrderGoods.objects.create(
                        order=order,
                        sku=sku,
                        count=sku_count,
                        price=sku.price,
                    )

                    # 保存商品订单中总价和总数量
                    order.total_count += sku_count
                    order.total_amount += sku_count * sku.price

                    # 测试用的，可以删除（注意下方的7是当前我在测试时一个用户的id小于7而另外一个是7，所以才写的7，根据实际编写即可）
                    # if request.user.id < 7:
                    #     for i in range(10):
                    #         print("用户{}正在延时{}提交中...".format(request.user.username, i + 1))
                    #         time.sleep(1)

                # 添加邮费和保存订单信息
                order.total_amount += order.freight
                order.save()
            except Exception as e:
                transaction.savepoint_rollback(save_id)
                return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '下单失败'})

            # 提交订单成功，显式的提交一次事务
            transaction.savepoint_commit(save_id)

        # 清除购物车中已结算的商品
        pl = redis_conn.pipeline()
        pl.hdel('carts_%s' % user.id, *selected)
        pl.srem('selected_%s' % user.id, *selected)
        pl.execute()

        # 响应提交订单结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '下单成功', 'order_id': order.order_id})


class OrderSuccessView(LoginRequiredMixin, View):
    def get(self, request):
        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = request.GET.get("pay_method")
        context = {
            'payment_amount': payment_amount,
            'order_id': order_id,
            'pay_method': pay_method,
        }

        return render(request, 'order_success.html', context=context)


class OrderCommentView(LoginRequiredMixin, View):
    def get(self, request):
        """展示商品评价页面"""
        # 接收参数
        order_id = request.GET.get('order_id')
        # 校验参数
        try:
            OrderInfo.objects.get(order_id=order_id, user=request.user)
        except OrderInfo.DoesNotExist:
            return http.HttpResponseNotFound('订单不存在')

        # 查询订单中未被评价的商品信息
        uncomment_goods = OrderGoods.objects.filter(order_id=order_id, is_commented=False)
        if not uncomment_goods:
            return http.HttpResponseServerError('订单商品信息出错')

        # 构造待评价商品数据
        uncomment_goods_list = []
        for goods in uncomment_goods:
            uncomment_goods_list.append({
                'order_id': goods.order.order_id,
                'sku_id': goods.sku.id,
                'name': goods.sku.name,
                'price': str(goods.price),
                'default_image_url': goods.sku.default_image,
                'comment': goods.comment,
                'score': goods.score,
                'is_anonymous': str(goods.is_anonymous),
            })

        # 渲染模板
        context = {
            'uncomment_goods_list': uncomment_goods_list
        }
        return render(request, 'order_comment.html', context)
